package com.workcell.workdata.im.component.function;

import com.farsunset.cim.model.Message;
import com.getui.push.v2.sdk.ApiHelper;
import com.getui.push.v2.sdk.GtApiConfiguration;
import com.getui.push.v2.sdk.api.PushApi;
import com.getui.push.v2.sdk.common.ApiResult;
import com.getui.push.v2.sdk.dto.req.Audience;
import com.getui.push.v2.sdk.dto.req.Settings;
import com.getui.push.v2.sdk.dto.req.message.PushChannel;
import com.getui.push.v2.sdk.dto.req.message.PushDTO;
import com.getui.push.v2.sdk.dto.req.message.PushMessage;
import com.getui.push.v2.sdk.dto.req.message.ios.Alert;
import com.getui.push.v2.sdk.dto.req.message.ios.Aps;
import com.getui.push.v2.sdk.dto.req.message.ios.IosDTO;
import com.workcell.workdata.im.component.event.ClientBindEvent;
import com.workcell.workdata.im.component.event.LogoutEvent;
import com.workcell.workdata.im.component.event.ThirdMessagePushEvent;
import com.workcell.workdata.im.component.redis.KeyValueRedisTemplate;
import com.workcell.workdata.im.configuration.properties.UniPushProperties;
import com.workcell.workdata.im.entity.Session;
import com.workcell.workdata.im.util.JSON;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;


@Component
@ConditionalOnProperty(name = {"hoxin.uni.push.enable"})
public class UniPushHandler{

    private static final String UNI_PUSH_CID = "UNI_PUSH_CID_%s";

    private static final String UNI_PUSH_UID = "UNI_PUSH_UID_%s";

    private static final String LOCK_KEY = "UNI_PUSH_LOCK_%s";

    private final Logger logger = LoggerFactory.getLogger(UniPushHandler.class);

    private final PushApi pushApi;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private KeyValueRedisTemplate keyValueRedisTemplate;

    @Resource
    private APNsAlertHelper apNsAlertHelper;

    @Autowired
    public UniPushHandler(UniPushProperties properties){

        GtApiConfiguration apiConfiguration = new GtApiConfiguration();

        apiConfiguration.setAppId(properties.getAppId());
        apiConfiguration.setAppKey(properties.getAppKey());
        apiConfiguration.setMasterSecret(properties.getMasterSecret());
        apiConfiguration.setDomain(properties.getDomain());
        pushApi = ApiHelper.build(apiConfiguration).creatApi(PushApi.class);

    }

    @EventListener(classes = LogoutEvent.class)
    public void onLogout(LogoutEvent event){
        keyValueRedisTemplate.delete(String.format(UNI_PUSH_CID,event.getUid()));
    }

    @EventListener(classes = ClientBindEvent.class)
    public void onUniPushBind(ClientBindEvent event) {

        /*
        账号在非uniapp终端登录，清除clientId
         */
        if (!event.isUniApp() || StringUtils.isBlank(event.getUniPushClientId())){
            keyValueRedisTemplate.delete(String.format(UNI_PUSH_CID,event.getUid()));
            return;
        }

        /*
         * 同设备多个账号登录，清除上一次登录的UID - CID关联记录
         */
        String lastUid = keyValueRedisTemplate.get(String.format(UNI_PUSH_UID,event.getUniPushClientId()));
        if (lastUid != null && !Objects.equals(lastUid,String.valueOf(event.getUid()))){
            keyValueRedisTemplate.delete(String.format(UNI_PUSH_CID,lastUid));
        }

        UniPushClient client = new UniPushClient();
        client.channel = event.getChannel();
        client.clientId = event.getUniPushClientId();
        keyValueRedisTemplate.set(String.format(UNI_PUSH_CID,event.getUid()), JSON.toJSONString(client));

        keyValueRedisTemplate.set(String.format(UNI_PUSH_UID,client.clientId),String.valueOf(event.getUid()));

    }

    @Async("apnsTaskExecutor")
    @EventListener(classes = ThirdMessagePushEvent.class,condition = "#root.args[0].isNotEmpty")
    public void accept(ThirdMessagePushEvent event){

        String key = String.format(LOCK_KEY, event.getTraceId());
        RLock lock = redissonClient.getLock(key);

        if (!lock.tryLock()) {
            return;
        }

        try {
            event.getMessageList().forEach(UniPushHandler.this::accept);
        } finally {
            lock.unlock();
        }

    }

    private void accept(Message message) {

        String data = keyValueRedisTemplate.get(String.format(UNI_PUSH_CID,message.getReceiver()));

        if(StringUtils.isBlank(data)) {
            return;
        }

        UniPushClient client = JSON.parse(data,UniPushClient.class);

        /*
         * 不集成android的离线推送，需要接入各个厂商的推送太鸡儿麻烦
         */
        if (Objects.equals(client.channel, Session.CHANNEL_UNI_ANDROID)){
            return;
        }


        /*
          ios离线apn通道推送的消息体
         */
        PushDTO<Audience> pushDTO = new PushDTO<>();
        pushDTO.setRequestId(UUID.randomUUID().toString());
        Settings settings = new Settings();
        pushDTO.setSettings(settings);
        settings.setTtl(3600000);

        Audience audience = new Audience();
        audience.addCid(client.clientId);
        pushDTO.setAudience(audience);

        PushChannel pushChannel = new PushChannel();

        Alert alert = new Alert();
        alert.setTitle(apNsAlertHelper.getTitle(message));
        alert.setBody(apNsAlertHelper.getBody(message));
        Aps aps = new Aps();
        aps.setContentAvailable(0);
        aps.setSound("default");
        aps.setAlert(alert);

        aps.put("id",message.getId());
        aps.put("action",message.getAction());
        aps.put("content",message.getContent());
        aps.put("sender",message.getSender());
        aps.put("receiver",message.getReceiver());
        aps.put("format",message.getFormat());
        aps.put("extra",message.getExtra());
        aps.put("timestamp",message.getTimestamp());

        IosDTO iosDTO = new IosDTO();
        iosDTO.setAps(aps);
        iosDTO.setType("notify");
        pushChannel.setIos(iosDTO);


        PushMessage pushMessage = new PushMessage();
        pushMessage.setTransmission(String.format("{title:\"%s\",content:\"%s\"}",alert.getTitle(),alert.getBody()));
        pushDTO.setPushMessage(pushMessage);

        pushDTO.setPushChannel(pushChannel);

        ApiResult<Map<String, Map<String, String>>> apiResult = pushApi.pushToSingleByCid(pushDTO);
        if (apiResult.isSuccess()) {
            logger.info("UniPush推送成功,uid:{},channel:{}", message.getReceiver(),client.channel);
        } else {
            logger.warn("UniPush推送失败,uid:{},channel:{},code:{}",message.getReceiver(),client.channel,apiResult.getCode());
        }

    }

    private static class UniPushClient{
        private String channel;
        private String clientId;

        public String getChannel() {
            return channel;
        }

        public String getClientId() {
            return clientId;
        }
    }
}
